#ifndef __HTTP_PARSER_H__
#define __HTTP_PARSER_H__

#include "pk_buff.h"
#include "types.h"
#include "url_info.h"
#include <ctype.h>

/* #define CONFIG_TRACK_ALL_HTTP_SESSION  */

#ifdef CONFIG_REDIRECT_404_ENABLE
#define MP_NF_MAX	  2000000
#define MP_NF_INIT	  MP_NF_MAX>>1
#define MP_NF_INCR 	  MP_NF_MAX>>3
#define NUM_OF_404     20000000
#endif

enum {
    METHOD_GET = 0,
    METHOD_POST,
    METHOD_HEAD,
    METHOD_PUT,
    METHOD_DELETE,
    METHOD_OPTIONS,
    METHOD_TRACE,
    METHOD_CONNECT,
    
    METHOD_COUNT,
};

/*
 * structure to hold request elements,
 * embed in pk_buff
 */
struct  http_request {
    /* fetch in request line */
    u8   _method;
    u8   _version;
	u16  server_port;
    char *_uri;
    char *_host;   /* may empty */
    u16  _uri_len;
    u16  _host_len;
    
    /* fetch in request header fields */
    char *h_host;          /* Host:*/
    char *x_host;        /* X-Online-Host: */
    u16   h_host_len;
    u16   x_host_len;

    char *path;
    char *param;
    u16  path_len;
    u16  param_len;
    
    char *ua;           /* User-Agent: */
	u32  ua_id;          /* 0 phone, 1 pc */
	int ua_flag;		/*	if this ua should be blocked	*/

    char *xw_prf;       /* X-Wap_profile: */
    u16  ua_len;
    u16  xw_prf_len;

    char *host;
    u16  host_len;

    char *accept;
	u16   accept_len;

#if defined( GD_JXH_PLATFORM) || defined(CONFIG_HTTP_REFER_MERGE_ENABLE)
	char *refer;
	u16   refer_len;
#endif

    struct url_info  *url_info;
    struct path_info *path_info;
    int    index;
};

struct http_response {
    u8   _version;
    u8   pad;
    u16  _code;
    char *content_type;
    u16  content_type_len;
    u32  content_length;

    char *server;
    u16  server_len;
    /* FIX ME !!*/
};

#ifdef CONFIG_REDIRECT_404_ENABLE
enum{
	HTTP_STATIC_NF = 0,
	HTTP_DYNAMIC_NF,
};

struct hlist_404_head{
	pthread_spinlock_t lock;
	struct list_head head;
};

struct http_404_group{
	struct hlist_404_head not_found[NUM_OF_404];
};

struct http_redirect_404{
//	int counter;
	int flags;
	char host[64];
	char path[192];
	u8	host_len;
	u8	path_len;
	short status;
	u64 timestamp;
	struct list_head link_redirect;
};
#endif


struct http_stat {
    int request_count;
	struct reassemble_list res_list;
};
    

int  http_stat_init(struct http_stat *stat);
void http_stat_clean(struct http_stat *stat);

int decode_http(struct pk_buff *pkb);
int http_parser_init();
void  http_parser_clean();

#ifdef CONFIG_REDIRECT_404_ENABLE
inline int http_get_redirect_nf_enable();
void http_set_redirect_nf_enable(int policy);
int http_set_redirect_location_detail(char *location);
int http_get_redirect_location_detail(char **location, int *len);
int http_redirect_find_path_response(char *host, int host_len, char *path, int path_len, int flags);
int do_nfound_url_modify(void *url);
int http_set_not_found_percent(void *loc);
int http_black_look_trie(char *key);
#endif


static inline int normalize_http_data(char *data_raw, int len, 
                    char *buf, int buf_len, char sep, char term)
{
    char *end0 = data_raw + len;
    char *end1 = buf + buf_len;
    register char *ptr0 = data_raw, *ptr1 = buf;
   
    while (ptr0 < end0 && ptr1 < end1) {
        if (*ptr0 == sep) {
            *ptr1++ = '\\';
			*ptr1++ = *ptr0;
			ptr0++;
            continue;
        }

        if (*ptr0 == term) {  /* drop */
            ptr0++;
		    continue;
		}

		if(*ptr0 == '\\') {
			*ptr1++ = '\\';
			*ptr1++ = '\\';
			ptr0++;
			continue;
		}

    	if (isprint(*ptr0)) 
            *ptr1++ = *ptr0++;
		else 
			ptr0++;
    }
    return (ptr1 - buf);
}

static inline int valid_http_host(const char *host, u16 *len) {
	char *ptr = (char *)host;
	register int l = *len;

	while(l) {
		if(isprint(*ptr) == 0) {
			return -1;
		}
		if(*ptr == '\n' || *ptr == '\r' || *ptr == 0) {
			*len = ptr - host;
			return 0;
		}
		else {
			l --;
			ptr ++;
		}
	}

	return 0;
}

#endif

